<?php
/**
 * Nordic Repository
 * 
 * LICENSE
 * 
 * The new BSD license is applied on this source-file. For further
 * information please visit http://license.nordic-dev.de/newbsd.txt
 * or send an email to andre.moelle@gmail.com.
 */

/**
 * Necessary includes.
 */
Zend_Loader::loadClass('Nordic_Pagebuilder_Decorator');
Zend_Loader::loadClass('Nordic_Pagebuilder_Decorated');

/**
 * This class manages all decorators.
 * 
 * @category   Nordic
 * @package    Nordic_Pagebuilder
 * @copyright  2007 Nordic Development
 * @license    http://license.nordic-dev.de/newbsd.txt (New-BSD license)
 * @author     Andre Moelle <andre.moelle@gmail.com>
 * @version    $Id: DecoratorManager.php 3 2007-07-08 09:21:42Z andre.moelle $
 */
class Nordic_Pagebuilder_DecoratorManager
{
	/**
	 * Prefix for the default decorators.
	 * 
	 * @const string
	 */
	const DEFAULT_PREFIX = 'Nordic_Pagebuilder_Decorator_';
	
	/**
	 * Default suffix for the decorator-files.
	 * 
	 * @const string
	 */
	const DEFAULT_SUFFIX = '.php';
	
	/**
	 * Array with possible decorators.
	 * 
	 * @var array
	 */
	private $_decorators = array();
	
	/**
	 * Instance of the decorator-manager.
	 * 
	 * @var Nordic_Pagebuilder_DecoratorManager
	 */
	private static $_instance = null;
	
	/**
	 * Is not instantiable outside this class.
	 * 
	 * @param void
	 * @return void
	 */
	private function __construct ()
	{
		$this->_loadDefaultDecorators();
	}
	
	/**
	 * Loads the default decorators.
	 * 
	 * @throws Nordic_Pagebuilder_Exception
	 * @param void
	 * @return integer
	 */
	private function _loadDefaultDecorators ()
	{
		$result = 0;
		$array = glob(
			NORDIC_LIB . str_replace('_', '/', self::DEFAULT_PREFIX) . '*' . self::DEFAULT_SUFFIX
		);
		
		if($array === false)
		{
			return 0;
		}
		
		foreach($array as $path)
		{
			$name = basename($path, self::DEFAULT_SUFFIX);
			$class = self::DEFAULT_PREFIX . $name;
			
			Zend_Loader::loadClass($class);
			$this->appendDecorator($name, $class);
			
			$result++;
		}
		
		return $result;
	}
	
	/**
	 * Tests if the given classname is a decorator.
	 * 
	 * If it is not, an exception will be thrown.
	 * 
	 * @throws Nordic_Pagebuilder_Exception
	 * @param string $class possible decorator class
	 * @return void
	 */
	private function _testClass ($class)
	{
		$refl = new ReflectionClass($class);
		
		if(!$refl->isSubclassOf(new ReflectionClass('Nordic_Pagebuilder_Decorator')))
		{
			throw new Nordic_Pagebuilder_Exception(
				'Class "' . $class . '" is not a decorator'
			);
		}
	}
	
	/**
	 * Tests if the given object is a decorator.
	 * 
	 * If it is not a Nordic_Pagebuilder_Exception will be thrown.
	 * Otherwise the class-name of the decorator is returned.
	 * 
	 * @throws Nordic_Pagebuilder_Exception
	 * @param object $obj possible decorator object
	 * @return string
	 */
	private function _testObject ($obj)
	{
		$class = get_class($obj);
		
		if(!($obj instanceof Nordic_Pagebuilder_Decorator))
		{
			throw new Nordic_Pagebuilder_Exception(
				'Class "' . $class . '" is not a decorator'
			);
		}
		
		return $class;
	}
	
	/**
	 * Appends a decorator to the internal decorator-list.
	 * 
	 * If any errors occur, an exception will be thrown.
	 * 
	 * @throws Nordic_Pagebuilder_Exception
	 * @param string $name name of the decorator
	 * @param mixed $decorator new decorator (classname or object)
	 * @return boolean
	 */
	public function appendDecorator ($name, $decorator)
	{
		if($this->find($name))
		{
			throw new Nordic_Pagebuilder_Exception('Decorator "' . $name . '" already exists.');
		}
		
		if(is_object($decorator))
		{
			$decorator = $this->_testObject($decorator);
		}
		else
		{
			$this->_testClass($decorator);
		}
		
		$this->_decorators[$name] = $decorator;
		
		return true;
	}
	
	/**
	 * Finds the class of a decorator.
	 * 
	 * If the requested decorator does not exist, an empty string
	 * is returned instead.
	 * 
	 * @param string $name name of the decorator
	 * @return string
	 */
	public function find ($name)
	{
		if(!isset($this->_decorators[$name]))
		{
			return '';
		}
		
		return $this->_decorators[$name];
	}
	
	/**
	 * Returns a decorator-object.
	 * 
	 * If the decorator does not exist, an exception will be thrown.
	 * 
	 * @throws Nordic_Pagebuilder_Exception
	 * @param string $name decorator-name
	 * @param array $args arguments
	 * @return Nordic_Pagebuilder_Decorator
	 */
	public function getDecorator ($name, array $args = array())
	{
		if(($class = $this->find($name)) === '')
		{
			throw new Nordic_Pagebuilder_Exception(
				'Decorator "' . $name . '" could not be found'
			);
		}
		
		return new $class($args);
	}
	
	/**
	 * Returns the instance of the manager.
	 * 
	 * @param void
	 * @return Nordic_Pagebuilder_DecoratorManager
	 */
	public static function getInstance ()
	{
		if(self::$_instance == null)
		{
			self::$_instance = new self();
		}
		
		return self::$_instance;
	}
	
	/**
	 * Removes a decorator.
	 * 
	 * If no one existed before, false is returned. Otherwise true.
	 * 
	 * @param string $name name of the decorator
	 * @return boolean
	 */
	public function removeDecorator ($name)
	{
		if(!$this->find($name))
		{
			return false;
		}
		
		unset($this->_decorators[$name]);
		
		return true;
	}
}
?>